---
title: "Select"
description: "A select displays a collapsible list of options and allows a user to select one or more of them."
---

import {selectContent} from "@/content/components/select";

# Select

A select displays a collapsible list of options and allows a user to select one or more of them.

<ComponentLinks component="select" reactAriaHook="useSelect" />

---

<CarbonAd/>

## Installation

<PackageManagers
  showGlobalInstallWarning
  commands={{
    cli: "npx heroui-cli@latest add select",
    npm: "npm install @heroui/select",
    yarn: "yarn add @heroui/select",
    pnpm: "pnpm add @heroui/select",
    bun: "bun add @heroui/select"
  }}
/>

## Import

HeroUI exports 3 select-related components:

- **Select**: The main component, which is a wrapper for the other components.
- **SelectSection**: The component that contains a group of select items.
- **SelectItem**: The component that represents a select item.

<ImportTabs
  commands={{
    main: 'import {Select, SelectSection, SelectItem} from "@heroui/react";',
    individual: 'import {Select, SelectSection, SelectItem} from "@heroui/select";',
  }}
/>

## Usage

<CodeDemo title="Usage" files={selectContent.usage} />

### Dynamic items

Select follows the [Collection Components API](https://react-spectrum.adobe.com/react-stately/collections.html), accepting both static and dynamic collections.

- **Static**: The usage example above shows the static implementation, which can be used when the full list of options is known ahead of time.
- **Dynamic**: The example below can be used when the options come from an external data source such as an API call, or update over time.

<CodeDemo title="Dynamic items" files={selectContent.dynamic} />

### Multiple Selection

You can use the `selectionMode="multiple"` property to allow multiple selection.

<CodeDemo title="Multiple Selection" files={selectContent.multiple} />

### Disabled

<CodeDemo title="Disabled" files={selectContent.disabled} />

### Disabled Items

You can disable specific items by using the `disabledKeys` property.

<CodeDemo title="Disabled Items" files={selectContent.disabledItems} />

### Required

If you pass the `isRequired` property to the select, it will have a `danger` asterisk at
the end of the label and the select will be required.

<CodeDemo title="Required" files={selectContent.required} />

### Sizes

<CodeDemo title="Sizes" files={selectContent.sizes} />

### Colors

<CodeDemo title="Colors" files={selectContent.colors} />

### Variants

<CodeDemo title="Variants" files={selectContent.variants} />

### Radius

<CodeDemo title="Radius" files={selectContent.radius} />

### Label Placements

You can change the position of the label by setting the `labelPlacement` property to `inside`, `outside` or `outside-left`.

<CodeDemo title="Label Placements" files={selectContent.labelPlacements} />

> **Note**: If the `label` is not passed, the `labelPlacement` property will be `outside` by default.

### Start Content

You can use the `startContent` properties to add content to the start of the select.

<CodeDemo title="Start Content" files={selectContent.startContent} />

### End Content

You can use the `endContent` properties to add content to the end of the select.

<CodeDemo title="End Content" files={selectContent.endContent} />

### Item Start & End Content

Since the `Select` component uses the [Listbox](/docs/components/listbox) component under the hood, you can
use the `startContent` and `endContent` properties of the `SelectItem` component to add content to the start
and end of the select item.

<CodeDemo title="Item Start Content" files={selectContent.itemStartContent} />

### Custom Selector Icon

By default the select uses a `chevron-down` icon as the selector icon which rotates when the select is open. You can
customize this icon by passing a custom one to the `selectorIcon` property.

<CodeDemo title="Custom Selector Icon" files={selectContent.customSelectorIcon} />

> **Note**: Use the `disableSelectorIconRotation` property to disable the rotation of the icon.

### Without Scroll Shadow

Select component uses the [ScrollShadow](/docs/components/scroll-shadow) under the hood to show a shadow when the select content is scrollable.
You can disable this shadow by passing using the `scrollShadowProps` property.

<CodeDemo title="Without Scroll Shadow" files={selectContent.withoutScrollShadow} />

> **Note**: You can also use the `showScrollIndicators` property to disable the scroll indicators.

### With Description

You can add a description to the select by passing the `description` property.

<CodeDemo title="With Description" files={selectContent.description} />

### With Error Message

You can combine the `isInvalid` and `errorMessage` properties to show an invalid select.

<CodeDemo title="With Error Message" files={selectContent.errorMessage} />

### Clear Button

If you pass the `isClearable` property to the select, it will have a clear button which will be visible only when a value is selected.

<CodeDemo title="Clear Button" files={selectContent.isClearable} />

### Controlled

You can use the `selectedKeys` and `onSelectionChange` / `onChange` properties to control the select value.

Using `onSelectionChange`:

<CodeDemo title="Controlled with onSelectionChange" files={selectContent.singleControlled} />

Using `onChange`:

<CodeDemo title="Controlled with onChange" files={selectContent.singleControlledOnChange} />

### Controlling the open state

You can control the open state of the select by using the `isOpen` and `onOpenChange` / `onClose` properties.

<CodeDemo title="Controlling the open state" files={selectContent.openState} />

### Custom Items

You can customize the select items by modifying the `SelectItem` children.

<CodeDemo title="Custom Items" files={selectContent.customItems} />

### Custom Render Value

By default the select will render the selected item's text value, but you can customize this by passing a `renderValue` function.

<CodeDemo title="Custom Render Value" files={selectContent.customRenderValue} />

The `renderValue` function receives the selected items as a parameter and must return a
`ReactNode`. Check the [Render Value Function](#render-value-function) section for more details.

### Asynchronous Loading

Select supports asynchronous loading, in the example below we are using a custom hook to fetch the [Pokemon API](https://pokeapi.co/api/v2/pokemon) data in combination with the `useInfiniteScroll` hook to load more data when the user reaches the end of the list.

The `isLoading` prop is used to show a loading indicator instead of the selector icon when the data is being fetched.

<PackageManagers
  commands={{
    npm: "npm install @heroui/use-infinite-scroll",
    yarn: "yarn add @heroui/use-infinite-scroll",
    pnpm: "pnpm add @heroui/use-infinite-scroll",
  }}
/>

```jsx
import {useInfiniteScroll} from "@heroui/use-infinite-scroll";
```

<Spacer y={2} />

<CodeDemo
  asIframe
  typescriptStrict={true}
  title="Asynchronous Loading"
  hideWindowActions={true}
  resizeEnabled={false}
  displayMode="always"
  files={selectContent.asyncLoadingItems}
  previewHeight="400px"
  iframeSrc="/examples/select/async-items-loading"
/>


### Virtualization

Select supports virtualization, which allows efficient rendering of large lists by only rendering items that are visible in the viewport. You can enable virtualization by setting the `isVirtualized` prop to `true`.

<CodeDemo
  title="Virtualization"
  files={selectContent.virtualization}
/>

> **Note**: The virtualization strategy is based on the [@tanstack/react-virtual](https://tanstack.com/virtual/latest) package, which provides efficient rendering of large lists by only rendering items that are visible in the viewport.

#### Ten Thousand Items

Here's an example of using virtualization with 10,000 items.

<CodeDemo title="Ten Thousand Items" files={selectContent.virtualizationTenThousand} />

#### Max Listbox Height

The `maxListboxHeight` prop is used to set the maximum height of the listbox. This is required when using virtualization. By default, it's set to `256`.

<CodeDemo title="Max Listbox Height" files={selectContent.virtualizationMaxListboxHeight} />

#### Custom Item Height

The `itemHeight` prop is used to set the height of each item in the listbox. This is required when using virtualization. By default, it's set to `32`.

> **Note**: If the height of the list items differs from the default due to `startContent` or other custom content, be sure to pass the correct value to `itemHeight` to prevent layout issues.

<CodeDemo title="Custom Item Height" files={selectContent.virtualizationCustomItemHeight} />

### With Sections

You can use the `SelectSection` component to group select items.

<CodeDemo title="With Sections" files={selectContent.sections} />

### Custom Sections Style

You can customize the sections style by using the `classNames` property of the `SelectSection` component.

<CodeDemo title="Custom Sections Style" files={selectContent.customSectionsStyle} />

### Multiple Select Controlled

You can use the same properties as the single select to control the multiple select, `selectedKeys` and `onSelectionChange` / `onChange`.

Using `onSelectionChange`:

<CodeDemo
  title="Multiple Selection Controlled with onSelectionChange"
  files={selectContent.multipleControlled}
/>

Using `onChange`:

<CodeDemo
  title="Multiple Selection Controlled with onChange"
  files={selectContent.multipleControlledOnChange}
/>

### Multiple With Chips

You can render any component as the select value by using the `renderValue` property. In this example we are
using the [Chip](/docs/components/chip) component to render the selected items.

<CodeDemo title="Multiple Selection with Chips" files={selectContent.multipleWithChips} />

> **Note**: Make sure to pass the `isMultiline` property to the `Select` component to allow the chips to wrap.

The `renderValue` function receives the selected items as a parameter and must return a
`ReactNode`. Check the [Render Value Function](#render-value-function) section for more details.

### Customizing the select

You can customize any slot of the select by using the `classNames` property. Select
component also provides the [popoverProps](/docs/components/popover#api) and [listboxProps](/docs/components/listbox#api) properties to customize
the popover and listbox components.

<CodeDemo title="Custom Styles" files={selectContent.customStyles} />


### Using `value` attribute in option

The [`value`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option#value) attribute is not directly supported in `SelectItem`. Instead, the `key` property should be used to set the `value` to be submitted in forms.

If you need to submit a specific `value` instead of the `key` during form submission, consider implementing a lookup map in your application.

## Slots

- **base**: The main wrapper of the select. This wraps the rest of the slots.
- **label**: The label of the select.
- **mainWrapper**: Wraps the `helperWrapper` and the `trigger` slots.
- **trigger**: The trigger of the select. This wraps the label the inner wrapper and the selector icon.
- **innerWrapper**: The wrapper of the select content. This wraps the start/end content and the select value.
- **selectorIcon**: The selector icon of the select. This is the icon that rotates when the select is open (`data-open`).
- **value**: The select value. This is also the slot that wraps the `renderValue` function result.
- **listboxWrapper**: The wrapper of the listbox. This wraps the listbox component, this slot is used on top of the scroll shadow component.
- **listbox**: The listbox component. This is the component that wraps the select items.
- **popoverContent**: The popover content slot. Use this to modify the popover content styles.
- **helperWrapper**: The wrapper of the helper text. This wraps the helper text and the error message.
- **description**: The description of the select.
- **errorMessage**: The error message of the select.
- **clearButton**: Clear button for select. Displayed when `isClearable` prop is true.
- **endWrapper**: Wrapper for endContent and clear button.
- **endContent**: end Content for select component.

## Data Attributes

`Select` has the following attributes on the `base` element:

- **data-filled**:
  Indicates if the select has a value, is focused, has start/end content or is open.
- **data-has-value**:
  Indicates if the select has selected item(s).
- **data-has-label**:
  Indicates if the select has a label. Based on `label` prop.
- **data-has-helper**:
  Indicates if the select has helper text. Based on `errorMessage` or `description` prop.
- **data-invalid**:
  Indicates if the select is invalid. Based on `isInvalid` prop.

`Select` has the following attributes on the `trigger` element:

- **data-open**:
  Indicates if the select is open.
- **data-disabled**:
  When the select trigger is disabled. Based on select `isDisabled` prop.
- **data-focus**:
  When the select trigger is being focused. Based on [useFocusRing](https://react-spectrum.adobe.com/react-aria/useFocusRing.html).
- **data-focus-visible**:
  When the select trigger is being focused with the keyboard. Based on [useFocusRing](https://react-spectrum.adobe.com/react-aria/useFocusRing.html).
- **data-pressed**:
  When the select trigger is pressed. Based on [usePress](https://react-spectrum.adobe.com/react-aria/usePress.html)
- **data-hover**:
  When the select trigger is being hovered. Based on [useHover](https://react-spectrum.adobe.com/react-aria/useHover.html)

`Select` has the following attributes on the `selectorIcon` element:

- **data-open**:
  Indicates if the select is open.

`SelectItem` has the following attributes on the `base` element:

- **data-disabled**:
  When the select item is disabled. Based on select `disabledKeys` prop.
- **data-selected**:
  When the select item is selected. Based on select `selectedKeys` prop.
- **data-hover**:
  When the select item is being hovered. Based on [useHover](https://react-spectrum.adobe.com/react-aria/useHover.html)
- **data-pressed**:
  When the select item is pressed. Based on [usePress](https://react-spectrum.adobe.com/react-aria/usePress.html)
- **data-focus**:
  When the select item is being focused. Based on [useFocusRing](https://react-spectrum.adobe.com/react-aria/useFocusRing.html).
- **data-focus-visible**:
  When the select item is being focused with the keyboard. Based on [useFocusRing](https://react-spectrum.adobe.com/react-aria/useFocusRing.html).

<Spacer y={4} />

## Accessibility

- Exposed to assistive technology as a button with a listbox popup using ARIA (combined with [Listbox](/docs/components/listbox)).
- Support for selecting a single option.
- Support for selecting multiple options.
- Support for disabled options.
- Support for sections.
- Labeling support for accessibility.
- Support for description and error message help text linked to the input via ARIA.
- Support for mouse, touch, and keyboard interactions.
- Tab stop focus management.
- Keyboard support for opening the listbox using the arrow keys, including automatically focusing the first or last item accordingly.
- Typeahead to allow selecting options by typing text, even without opening the listbox.
- Browser autofill integration via a hidden native `<select>` element.
- Mobile screen reader listbox dismissal support.

<Spacer y={4} />

## API

### Select Props

<APITable
  data={[
    {
      attribute: "children*",
      type: "ReactNode[]",
      description: "The children to render. Usually a list of SelectItem and SelectSection elements.",
      default: "-"
    },
    {
      attribute: "items",
      type: "Iterable<T>",
      description: "Item objects in the select. (dynamic)",
      default: "-"
    },
    {
      attribute: "selectionMode",
      type: "single | multiple",
      description: "The type of selection that is allowed in the collection.",
      default: "-"
    },
    {
      attribute: "selectedKeys",
      type: "all | Iterable<React.Key>",
      description: "The currently selected keys in the collection (controlled).",
      default: "-"
    },
    {
      attribute: "disabledKeys",
      type: "Iterable<React.Key>",
      description: "The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with.",
      default: "-"
    },
    {
      attribute: "defaultSelectedKeys",
      type: "all | Iterable<React.Key>",
      description: "The initial selected keys in the collection (uncontrolled).",
      default: "-"
    },
    {
      attribute: "variant",
      type: "flat | bordered | faded | underlined",
      description: "The variant of the select.",
      default: "flat"
    },
    {
      attribute: "color",
      type: "default | primary | secondary | success | warning | danger",
      description: "The color of the select.",
      default: "default"
    },
    {
      attribute: "size",
      type: "sm | md | lg",
      description: "The size of the select.",
      default: "md"
    },
    {
      attribute: "radius",
      type: "none | sm | md | lg | full",
      description: "The radius of the select.",
      default: "-"
    },
    {
      attribute: "placeholder",
      type: "string",
      description: "The placeholder of the select.",
      default: "Select an option"
    },
    {
      attribute: "labelPlacement",
      type: "inside | outside | outside-left",
      description: "The position of the label.",
      default: "inside"
    },
    {
      attribute: "label",
      type: "ReactNode",
      description: "The content to display as the label.",
      default: "-"
    },
    {
      attribute: "description",
      type: "ReactNode",
      description: "A description for the select. Provides a hint such as specific requirements for what to choose.",
      default: "-"
    },
    {
      attribute: "errorMessage",
      type: "ReactNode | ((v: ValidationResult) => ReactNode)",
      description: "An error message for the select.",
      default: "-"
    },
    {
      attribute: "startContent",
      type: "ReactNode",
      description: "Element to be rendered in the left side of the select.",
      default: "-"
    },
    {
      attribute: "endContent",
      type: "ReactNode",
      description: "Element to be rendered in the right side of the select.",
      default: "-"
    },
    {
      attribute: "selectorIcon",
      type: "ReactNode",
      description: "Element to be rendered as the selector icon.",
      default: "-"
    },
    {
      attribute: "scrollRef",
      type: "React.RefObject<HTMLElement>",
      description: "A ref to the scrollable element.",
      default: "-"
    },
    {
      attribute: "spinnerRef",
      type: "React.RefObject<HTMLElement>",
      description: "A ref to the spinner element.",
      default: "-"
    },
    {
      attribute: "maxListboxHeight",
      type: "number",
      description: "The maximum height of the listbox in pixels. Required when using virtualization.",
      default: "256"
    },
    {
      attribute: "itemHeight",
      type: "number",
      description: "The fixed height of each item in pixels. Required when using virtualization.",
      default: "32"
    },
    {
      attribute: "isVirtualized",
      type: "boolean",
      description: "Whether to enable virtualization. By default, it's enabled when the number of items exceeds 50.",
      default: "undefined"
    },
    {
      attribute: "fullWidth",
      type: "boolean",
      description: "Whether the select should take up the width of its parent.",
      default: "true"
    },
    {
      attribute: "isOpen",
      type: "boolean",
      description: "Whether the select is open by default (controlled).",
      default: "-"
    },
    {
      attribute: "defaultOpen",
      type: "boolean",
      description: "Whether the select is open by default (uncontrolled).",
      default: "-"
    },
    {
      attribute: "isRequired",
      type: "boolean",
      description: "Whether user select is required on the select before form submission.",
      default: "false"
    },
    {
      attribute: "isDisabled",
      type: "boolean",
      description: "Whether the select is disabled.",
      default: "false"
    },
    {
      attribute: "isMultiline",
      type: "boolean",
      description: "Whether the select should allow multiple lines of text.",
      default: "false"
    },
    {
      attribute: "isInvalid",
      type: "boolean",
      description: "Whether the select is invalid.",
      default: "false"
    },
    {
      attribute: "isClearable",
      type: "boolean",
      description: "Whether clear button is visible or not.",
      default: "false"
    },
    {
      attribute: "validationState",
      type: "valid | invalid",
      description: "Whether the select should display its \"valid\" or \"invalid\" visual styling. (Deprecated) use isInvalid instead.",
      default: "-"
    },
    {
      attribute: "showScrollIndicators",
      type: "boolean",
      description: "Whether the select should show scroll indicators when the listbox is scrollable.",
      default: "true"
    },
    {
      attribute: "autoFocus",
      type: "boolean",
      description: "Whether the select should be focused on the first mount.",
      default: "false"
    },
    {
      attribute: "disallowEmptySelection",
      type: "boolean",
      description: "Whether the collection allows empty selection.",
      default: "false"
    },
    {
      attribute: "disableAnimation",
      type: "boolean",
      description: "Whether the select should be animated.",
      default: "true"
    },
    {
      attribute: "disableSelectorIconRotation",
      type: "boolean",
      description: "Whether the select should disable the rotation of the selector icon.",
      default: "false"
    },
    {
      attribute: "hideEmptyContent",
      type: "boolean",
      description: "Whether the listbox will be prevented from opening when there are no items.",
      default: "false"
    },
    {
      attribute: "popoverProps",
      type: "PopoverProps",
      description: "Props to be passed to the popover component.",
      default: "-"
    },
    {
      attribute: "listboxProps",
      type: "ListboxProps",
      description: "Props to be passed to the listbox component.",
      default: "-"
    },
    {
      attribute: "scrollShadowProps",
      type: "ScrollShadowProps",
      description: "Props to be passed to the scroll shadow component.",
      default: "-"
    },
    {
      attribute: "classNames",
      type: "Partial<Record<\"base\"｜ \"label\"｜ \"trigger\"｜ \"mainWrapper\" ｜ \"innerWrapper\"｜ \"selectorIcon\" ｜ \"value\" ｜ \"listboxWrapper\"｜ \"listbox\" ｜ \"popoverContent\" ｜ \"helperWrapper\" ｜ \"description\" ｜ \"errorMessage\", string>>",
      description: "Allows to set custom class names for the Select slots.",
      default: "-"
    }
  ]}
/>

### Select Events

<APITable
  data={[
    {
      attribute: "onClose",
      type: "() => void",
      description: "Callback fired when the select popover is closed.",
      default: "-"
    },
    {
      attribute: "onOpenChange",
      type: "(isOpen: boolean) => void",
      description: "Callback fired when the select popover is opened or closed.",
      default: "-"
    },
    {
      attribute: "onSelectionChange",
      type: "(keys: \"all\" | Set<React.Key> & {anchorKey?: string; currentKey?: string}) => void",
      description: "Callback fired when the selected keys change.",
      default: "-"
    },
    {
      attribute: "onClear",
      type: "() => void",
      description: "Handler that is called when the clear button is clicked."
    },
    {
      attribute: "onChange",
      type: "React.ChangeEvent<HTMLSelectElement>",
      description: "Native select change event, fired when the selected value changes.",
      default: "-"
    },
    {
      attribute: "renderValue",
      type: "RenderValueFunction",
      description: "Function to render the value of the select. It renders the selected item by default.",
      default: "-"
    }
  ]}
/>

---

### SelectItem Props

Check the [ListboxItem](/docs/components/listbox#listboxitem-props) props.

### SelectItem Events

Check the [ListboxItem](/docs/components/listbox#listboxitem-events) events.

### SelectSection Props

Check the [ListboxSection](/docs/components/listbox#listboxsection-props) props.

---

### Types

#### Render Value Function

The `T` type is the type of the data passed to the select `items`.

```tsx
export type SelectedItemProps<T> = {
  /** A unique key for the item. */
  key?: Key;
  /** The props passed to the item. */
  props?: Record<string, any>;
  /** The item data. */
  data?: T | null;
  /** An accessibility label for this item. */
  "aria-label"?: string;
  /** The rendered contents of this item (e.g. JSX). */
  rendered?: ReactNode;
  /** A string value for this item, used for features like typeahead. */
  textValue?: string;
  /** The type of item this item represents. */
  type?: string;
};

type SelectedItems<T> = Array<SelectedItemProps<T>>;

renderValue: (items: SelectedItems<T>) => ReactNode;
```
